import streamlit as st
import yaml
import time
import os
import datetime
from besins_selenium_downloaders.config import *
from besins_selenium_downloaders.streamlit_tools import configure_page_navigation
from besins_selenium_downloaders.file_manager import (
    get_number_of_websites,
    get_website_names,
    map_site_to_task_id,
    map_site_to_url,
)
from besins_selenium_downloaders.logger import logger, log_function_call
import pandas as pd


class ConfigEditor:
    def __init__(self):
        self.config = load_configuration()
        self.setup_page_config()
        configure_page_navigation("config_editor")

        if "dates" not in self.config:
            today = datetime.date.today()
            one_month_ago = today - pd.DateOffset(days=30)
            self.config["dates"] = {
                "start_date": one_month_ago.strftime("%Y-%m-%d"),
                "end_date": today.strftime("%Y-%m-%d")
            }
            update_configuration(self.config)  

        if "chrome_options" not in self.config:
            self.config["chrome_options"] = {
                "ignore-certificate-errors": "true"
            }
            update_configuration(self.config)  

        if "directories" not in self.config:
            self.config["directories"] = {
                "browser_downloads_directory": "./Downloads-tmp"
            }
            update_configuration(self.config)  

        # Ensure 'secret_files' key exists in the config
        if "secret_files" not in self.config:
            self.config["secret_files"] = {
                "dotenv": ".env",
                "xlsx": "NAN.xlsx"
            }
            update_configuration(self.config)  
        else:
            # Ensure 'xlsx' key exists within 'secret_files'
            if "xlsx" not in self.config["secret_files"]:
                self.config["secret_files"]["xlsx"] = "NAN.xlsx"
                update_configuration(self.config)  

        # Ensure 'selenium' key exists in the config
        if "selenium" not in self.config:
            self.config["selenium"] = {
                "chrome_driver_path": "/path/to/chromedriver",
                "firefox_driver_path": "/path/to/geckodriver",
                "headless": "false"
            }
            update_configuration(self.config)  
        else:
            # Ensure 'headless' key exists within 'selenium'
            if "headless" not in self.config["selenium"]:
                self.config["selenium"]["headless"] = "false"
                update_configuration(self.config)  

        # Ensure 'streamlit' key exists in the config
        if "streamlit" not in self.config:
            self.config["streamlit"] = {
                "address": "127.0.0.1",
                "allow_run_on_save": "true",
                "port": 8501
            }
            update_configuration(self.config)  

        if "sort_by_task_id" not in self.config:
            self.config["sort_by_task_id"] = "true"
            update_configuration(self.config)  

        self.count = 0
        self.main()

    def edit_chrome_options(self):
        """Edit Chrome-specific options."""
        st.markdown(
            "<div class='section-header'>🔧 Chrome Options</div>",
            unsafe_allow_html=True,
        )
        chrome_options = self.config.get("chrome_options", {})

        # 🔒 Ignore Certificate Errors
        ignore_certificate_errors = st.checkbox(
            "🔒 Ignore Certificate Errors",
            value=chrome_options.get("ignore-certificate-errors", False),
            help="Ignore SSL certificate errors in Chrome.",
            key="ignore_certificate_errors",
        )
        self.config["chrome_options"]["ignore-certificate-errors"] = str(
            ignore_certificate_errors
        ).lower()
        update_configuration(self.config)

    def setup_page_config(self):
        """Set up the Streamlit page configuration and custom CSS."""
        st.set_page_config(
            page_title="⚙️ Configuration Editor",
            page_icon="⚙️",
            layout="wide",
            initial_sidebar_state="expanded",
        )

        # Load and inject CSS
        common_css_path = os.path.join(os.path.dirname(__file__), "../css/common.css")
        with open(common_css_path) as f:
            st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)

        css_path = os.path.join(os.path.dirname(__file__), "../css/config_editor.css")
        with open(css_path) as f:
            st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)

    def main(self):
        """Main method to display and edit configuration settings."""
        st.markdown(
            '<h1 class="common-title">⚙️ Configuration Editor</h1>',
            unsafe_allow_html=True,
        )

        # Improved informational message about automatic saving
        st.warning(
            "⚠️ All changes on this page are automatically saved to `config.yml` in real-time. Please ensure accuracy before making modifications."
        )

        # Display and edit configuration sections
        self.edit_selenium_settings()
        self.edit_streamlit_settings()
        self.edit_dates()
        self.edit_chrome_options()
        self.edit_websites()

        # View config.yml Section
        config_path = os.path.join(os.getcwd(), "config.yml")
        if os.path.exists(config_path):
            last_updated = datetime.datetime.fromtimestamp(
                os.path.getmtime(config_path)
            ).strftime("%Y-%m-%d %H:%M:%S")
            with st.expander(
                f"View config.yml (Last Updated: {last_updated})",
                icon="📄",
                expanded=True,
            ):
                st.code(f"Location: {config_path}")
                with open(config_path, "r") as file:
                    config_content = file.read()
                st.code(config_content, language="yaml")
        else:
            st.error(f"❌ `config.yml` not found at {config_path}")

    def edit_selenium_settings(self):
        """Edit Selenium related configurations."""
        st.markdown(
            "<div class='section-header'>🔧 Selenium Settings</div>",
            unsafe_allow_html=True,
        )
        selenium_config = self.config.get("selenium", {})

        col1, col2 = st.columns(2)

        with col1:
            # Headless Mode
            headless = st.checkbox(
                "Headless Mode",
                value=str(selenium_config.get("headless", False)).lower() == "true",
                help="Run browsers in headless mode.",
                key="headless_mode",
            )
            self.config["selenium"]["headless"] = str(headless).lower()
            update_configuration(self.config)
            time.sleep(0.3)

    def edit_streamlit_settings(self):
        """Edit Streamlit server configurations."""
        st.markdown(
            "<div class='section-header'>📡 Streamlit Server Settings</div>",
            unsafe_allow_html=True,
        )
        streamlit_config = self.config.get("streamlit", {})

        col1, col2 = st.columns(2)

        with col1:
            # Streamlit Address
            address = st.selectbox(
                "🌐 Streamlit Address",
                options=["127.0.0.1", "0.0.0.0"],
                index=(
                    0
                    if streamlit_config.get("address", "127.0.0.1") == "127.0.0.1"
                    else 1
                ),
                help="Address where the Streamlit server listens.",
                key="streamlit_address",
            )
            self.config["streamlit"]["address"] = address
            update_configuration(self.config)

        with col2:
            # Streamlit Port
            port = st.number_input(
                "🔢 Streamlit Port",
                min_value=1024,
                max_value=65535,
                value=int(streamlit_config.get("port", 8501)),
                step=1,
                help="Port number for the Streamlit server.",
                key="streamlit_port",
            )
            self.config["streamlit"]["port"] = port
            update_configuration(self.config)

        with col1:
            # Allow Run on Save
            allow_run_on_save = st.checkbox(
                "🔄 Allow Run on Save",
                value=str(streamlit_config.get("allow_run_on_save", True)).lower()
                == "true",
                help="Automatically rerun the app upon saving changes.",
                key="allow_run_on_save",
            )
            self.config["streamlit"]["allow_run_on_save"] = str(
                allow_run_on_save
            ).lower()
            update_configuration(self.config)
            time.sleep(0.3)

    def edit_dates(self):
        """Edit date-related configurations."""
        st.markdown(
            "<div class='section-header'>📅 Date Settings</div>", unsafe_allow_html=True
        )

        dates_config = self.config.get("dates", {})

        if "start_date" not in st.session_state:
            st.session_state.start_date = None
        if "end_date" not in st.session_state:
            st.session_state.end_date = None
        if "count" not in st.session_state:
            st.session_state.count = 0

        # Calculate dates
        thirty_days_ago = (datetime.date.today() - pd.DateOffset(days=30)).date()
        start_date_str = dates_config.get(
            "start_date", thirty_days_ago.strftime("%Y-%m-%d")
        )
        today = datetime.date.today()
        end_date_str = dates_config.get("end_date", today.strftime("%Y-%m-%d"))

        # Convert string dates back to datetime.date
        start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d").date()
        end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d").date()

        col1, col2 = st.columns(2)
        with col1:
            if st.button(
                f"🗓️  Set Start Date to 30 Days Ago ({thirty_days_ago})",
                key="set_start_date_30",
            ):
                st.session_state.start_date = thirty_days_ago
                dates_config["start_date"] = (
                    st.session_state.start_date.strftime("%Y-%m-%d")
                )
                st.session_state.count += 1
                self.config["dates"] = dates_config
                update_configuration(self.config)

        with col2:
            if st.button(
                f"🗓️  Set End Date to Today ({today})",
                key="set_end_date_today",
            ):
                st.session_state.end_date = today
                dates_config["end_date"] = st.session_state.end_date.strftime(
                    "%Y-%m-%d"
                )
                self.config["dates"] = dates_config
                st.session_state.count += 1
                update_configuration(self.config)

        col1, col2 = st.columns(2)

        with col1:
            start_date_input = st.date_input(
                "📆 Start Date",
                value=(
                    st.session_state.start_date
                    if st.session_state.start_date
                    else start_date
                ),
                help="Start date for the tasks.",
                key=f"start_date_input_{st.session_state.count}",
            )
            st.session_state.start_date = start_date_input
            self.config["dates"]["start_date"] = start_date_input.strftime(
                "%Y-%m-%d"
            )
            update_configuration(self.config)

        with col2:
            end_date_input = st.date_input(
                "📆 End Date",
                value=(
                    st.session_state.end_date if st.session_state.end_date else end_date
                ),
                help="End date for the tasks.",
                key=f"end_date_input_{st.session_state.count}",
            )
            st.session_state.end_date = end_date_input
            self.config["dates"]["end_date"] = end_date_input.strftime(
                "%Y-%m-%d"
            )
            update_configuration(self.config)

    def edit_websites(self):
        """Edit website configurations, including adding and removing websites."""
        st.markdown(
            "<div class='section-header'>🌐 Websites Configuration</div>",
            unsafe_allow_html=True,
        )
        websites_config = self.config.get("websites", {})

        # 🔽 Add Excel File Selectbox
        st.markdown(
            "<div class='subsection-header'>📂 Select Excel File</div>",
            unsafe_allow_html=True,
        )

        # List all .xlsx files in the current directory
        current_dir = os.getcwd()
        xlsx_files = [
            file for file in os.listdir(current_dir) if file.endswith(".xlsx")
        ]

        # Get the current selected xlsx from config
        current_xlsx = self.config.get("secret_files", {}).get("xlsx", "")

        # Excel File Selectbox
        selected_xlsx = st.selectbox(
            "🔍 Choose Excel File",
            options=xlsx_files,
            index=xlsx_files.index(current_xlsx) if current_xlsx in xlsx_files else 0,
            help="Select the Excel file to use for website configurations.",
            key="select_excel_file",
        )

        # Update config with selected xlsx
        self.config["secret_files"]["xlsx"] = selected_xlsx
        update_configuration(self.config)

        # 🔼 End of Excel File Selectbox

        # Subsection for Sorting Websites
        st.markdown(
            "<div class='subsection-header'>🔀 Sorting Preferences for Websites in config.yml</div>",
            unsafe_allow_html=True,
        )

        # Checkbox to sort websites by Task ID
        sort_by_task_id = st.checkbox(
            "📊 Sort Websites by Task ID in config.yml",
            value=self.config.get("sort_by_task_id", "true").lower() == "true",
            help="Toggle to sort websites either by their Task ID or alphabetically in config.yml.",
            key="sort_by_task_id",
        )

        # Update the configuration based on the checkbox
        self.config["sort_by_task_id"] = str(sort_by_task_id).lower()
        update_configuration(self.config)
        update_configuration(self.config)

        # Subsection for Removing Websites
        st.markdown(
            "<div class='subsection-header'>🗑️ Remove Websites</div>",
            unsafe_allow_html=True,
        )

        # Get website names and their corresponding Task IDs and URLs from self.config
        sites = list(websites_config.keys())
        site_task_map = {
            site: websites_config[site].get("index", "TASK00000000") for site in sites
        }

        # Generate task_url_map based on current websites
        task_url_map = map_task_id_to_url()  # This should map task IDs to URLs
        site_url_map = {
            site: task_url_map.get(task_id, "🌐 N/A")
            for site, task_id in site_task_map.items()
        }

        if not sites:
            st.info("📄 No websites configured yet.")

        # Determine the maximum length of site names for alignment
        max_site_name_length = max(len(site) for site in sites) if sites else 0

        # Prepare website options with SiteName | TaskID | URL
        website_options = [
            f"{site:<{max_site_name_length + 1}} | {site_task_map.get(site, 'TASK00000000')} | {site_url_map.get(site, '🌐 N/A')}"
            for site in sites
        ]

        col1, col2 = st.columns([3, 1])

        with col1:
            selected_website = st.selectbox(
                "🗑️ Select Website to Remove",
                options=website_options,
                help="Choose a website to remove from the configuration.",
            )

        with col2:
            remove_button = st.button(
                "🗑️ Remove",
                help="Remove the selected website from the configuration.",
                key="remove_website_button",
            )
            if remove_button:
                site_to_remove = selected_website.split(" | ")[0].strip()
                logger.info(f"site_to_remove : {site_to_remove}")
                if site_to_remove in websites_config.keys():
                    logger.info(f"self.config before removal: {self.config}")

                    try:
                        removed_site = websites_config.pop(site_to_remove)
                    except Exception as e:
                        logger.error(e)
                        st.error(f"❌ Failed to remove website: {e}")
                        return

                    self.config["websites"] = websites_config
                    update_configuration(self.config)

                    logger.info(
                        f"Removed site: {site_to_remove}, config: {self.config}"
                    )
                    st.success(f"✅ Removed website: {site_to_remove}")
                    logger.debug(
                        f"Website '{site_to_remove}' removed. Current websites: {self.config['websites']}"
                    )
                else:
                    st.warning(f"⚠️ Website '{site_to_remove}' does not exist.")
                    logger.warning(
                        f"Attempted to remove non-existent website: {site_to_remove}"
                    )

        # Subsection for Adding Websites
        st.markdown(
            "<div class='subsection-header'>➕ Add Websites</div>",
            unsafe_allow_html=True,
        )

        # Add a new website
        col3, col4 = st.columns([3, 1])

        with col3:
            new_website_name = st.text_input(
                "📝 New Website Name",
                key="new_website_name",
                help="Enter the name of the new website to add.",
            )
            new_task_id = st.text_input(
                "🆔 New Task ID",
                key="new_task_id",
                help="Enter the Task ID for the new website.",
            )

        with col4:
            add_button = st.button(
                "➕ Add Website",
                help="Add a new website to the configuration.",
                key="add_website",
            )
            if add_button:
                new_website_name = new_website_name.strip()
                new_task_id = new_task_id.strip()
                if new_website_name and new_task_id:
                    if new_website_name in websites_config:
                        st.warning("⚠️ Website already exists.")
                        logger.warning(
                            f"Attempted to add existing website: {new_website_name}"
                        )
                    else:
                        self.config["websites"][new_website_name] = {
                            "index": new_task_id
                        }
                        update_configuration(self.config)
                        st.success(f"✅ Added website: {new_website_name}")
                        logger.debug(
                            f"Website '{new_website_name}' added. Current websites: {self.config['websites']}"
                        )
                else:
                    st.warning("⚠️ Please provide both **Site Name** and **Task ID**.")
                    logger.warning(
                        "Attempted to add website with incomplete information."
                    )


if __name__ == "__main__":
    ConfigEditor()
